﻿using System;
using NUnit.Framework;
using Sessionizer.Tests.Abstraction;

namespace Sessionizer.Tests
{
    public abstract class AbstractTest
    {
        private readonly object _syncRoot = new object();
        private volatile IIoCContainer _container;


        /// <summary>
        ///     Container of individual test - child of FixtureContainer.
        ///     Can be accessed only during Test ans TestSetup.
        /// </summary>
        protected IIoCContainer Container
        {
            get
            {
                lock (_syncRoot)
                {
                    if (_container == null)
                    {
                        throw new InvalidOperationException();
                    }
                    return _container;
                }
            }
            private set
            {
                lock (_syncRoot)
                {
                    _container = value;
                }
            }
        }

        [TestFixtureSetUp]
        public void TestFixtureSetUp()
        {
            lock (_syncRoot)
            {
                IIoCContainerBuilder container = CreateContainer();
                FixtureConfigure(container);
                Container = container.Build();
                FixtureSetup();
            }
        }

        [SetUp]
        public void SetUp()
        {
            lock (_syncRoot)
            {
                TestSetup();
            }
        }

        /// <summary>
        ///     Creates container instance
        /// </summary>
        /// <returns></returns>
        protected abstract IIoCContainerBuilder CreateContainer();


        [TearDown]
        public void TearDown()
        {
            lock (_syncRoot)
            {
                TestCleanup();
            }
        }

        [TestFixtureTearDown]
        public void TestFixtureTearDown()
        {
            lock (_syncRoot)
            {
                IIoCContainer container = Container;
                FixtureCleanup();
                container.Dispose();
                Container = null;
            }
        }

        /// <summary>
        ///     Configures FixtureContainer
        /// </summary>
        /// <param name="container"></param>
        protected virtual void FixtureConfigure(IIoCContainerBuilder container)
        {
        }

        /// <summary>
        ///     Prepares FixtureContainer
        /// </summary>
        protected virtual void FixtureSetup()
        {
        }

        /// <summary>
        ///     Prepares Container
        /// </summary>
        protected virtual void TestSetup()
        {
        }


        /// <summary>
        ///     Cleares resources allocated during TestSetup
        /// </summary>
        protected virtual void TestCleanup()
        {
        }

        /// <summary>
        ///     Clears resources allocated during FixtureSetup
        /// </summary>
        protected virtual void FixtureCleanup()
        {
        }
    }
}